﻿using System;
using System.Text;
using FluentAssertions.Common;
using Xunit;

namespace Unity.String.Tests
{
    public class ShimsExtensionsTest
    {
        private static bool IsNumber(char symbol)
        {
            return '0' <= symbol && symbol <= '9';
        }
        
        [Fact]
        public void Int32ExtensionMethodsTest()
        {
            char testNumberSymbol = '2';
            #if NET60 || NETCOREAPP31
            Assert.True(Int32.IsNumber(testNumberSymbol));
            #else
            Assert.True(IsNumber(testNumberSymbol));
            #endif
            char testNotNumberSymbol = 'a';
            #if NET60 || NETCOREAPP31
            Assert.False(Int32.IsNumber(testNotNumberSymbol));
            #else
            Assert.False(IsNumber(testNotNumberSymbol));
            #endif

            int testNumberValue = -123456;
            ReadOnlySpan<char> testParseNumberValue = 
                new ReadOnlySpan<char>(testNumberValue.ToString().ToCharArray());
            int parseNumberResult = Int32.Parse(testParseNumberValue);
            Assert.Equal(testNumberValue, parseNumberResult);
            
            ReadOnlySpan<char> testParseNotNumberValue = 
                new ReadOnlySpan<char>(("abc" + testNumberValue.ToString()).ToCharArray());
            int parseNotResult = Int32.Parse(testParseNotNumberValue);
            Assert.Equal(0, parseNotResult);
        }

        [Fact]
        public void ShimsExtensionMethodsTest()
        {
            string testEmptyStringValue = "";
            byte[] testEmptyByteBuffer = new byte[testEmptyStringValue.Length];
            int processingEmptyBytes = 
                ShimsExtensions.GetBytes(Encoding.ASCII, 
                    testEmptyStringValue.AsSpan(), testEmptyByteBuffer.AsSpan());
            Assert.Equal(processingEmptyBytes, testEmptyByteBuffer.Length);
            
            string testStringValue = "Lorem Ipsum";
            byte[] testByteBuffer = new byte[testStringValue.Length];
            int processingBytes = 
                ShimsExtensions.GetBytes(Encoding.ASCII, 
                    testStringValue.AsSpan(), testByteBuffer.AsSpan());
            Assert.Equal(processingBytes, testByteBuffer.Length);

            Guid testGuid = Guid.NewGuid();
            char[] testGuidCharsBuffer = new char[1024];
            bool tryFormatGuidResult = ShimsExtensions.TryFormat(testGuid,
                testGuidCharsBuffer.AsSpan(), out var testGuidCharsWritten);
            int needWrittenGuidChars = 36;
            Assert.Equal(needWrittenGuidChars, testGuidCharsWritten);
            Assert.True(tryFormatGuidResult);
            
            char[] testGuidEmptyCharsBuffer = Array.Empty<char>();
            bool tryFormatGuidEmptyResult = ShimsExtensions.TryFormat(testGuid,
                testGuidEmptyCharsBuffer.AsSpan(), 
                out var testGuidEmptyCharsWritten);
            int needWrittenEmptyGuidChars = 0;
            Assert.Equal(needWrittenEmptyGuidChars, testGuidEmptyCharsWritten);
            Assert.False(tryFormatGuidEmptyResult);
            
            TimeSpan testTimeSpan = DateTime.Today.TimeOfDay;
            char[] testTimeSpanCharsBuffer = new char[1024];
            ShimsExtensions.TryFormat(testTimeSpan,
                testTimeSpanCharsBuffer.AsSpan(), out var testTimeSpanCharsWritten);
            int needWrittenTimeSpanChars = 8;
            Assert.Equal(needWrittenTimeSpanChars, testTimeSpanCharsWritten);
            Assert.True(testTimeSpanCharsWritten > 0);
            
            char[] testTimeSpanEmptyCharsBuffer = Array.Empty<char>();
            bool tryFormatBoolResult = ShimsExtensions.TryFormat(testTimeSpan,
                testTimeSpanEmptyCharsBuffer.AsSpan(), 
                out var testTimeSpanEmptyCharsWritten);
            Assert.True(testTimeSpanEmptyCharsWritten == 0);
            Assert.False(tryFormatBoolResult);
            
            TimeSpan testTimeSpanWithEmptyFormat = DateTime.Today.TimeOfDay;
            char[] testTimeSpanWithEmptyFormatCharsBuffer = new char[1024];
            bool tryFormatTimeSpanWithEmptyFormatResult = 
                ShimsExtensions.TryFormat(testTimeSpanWithEmptyFormat,
                    testTimeSpanWithEmptyFormatCharsBuffer.AsSpan(), 
                    out var testTimeSpanWithEmptyFormatCharsWritten, "".AsSpan());
            int needWrittenTimeSpanWithEmptyFormatChars = 8;
            Assert.Equal(needWrittenTimeSpanWithEmptyFormatChars, 
                testTimeSpanWithEmptyFormatCharsWritten);
            Assert.True(tryFormatTimeSpanWithEmptyFormatResult);
            
            TimeSpan testTimeSpanWithFormat = DateTime.Today.TimeOfDay;
            char[] testTimeSpanWithFormatCharsBuffer = new char[1024];
            bool tryFormatTimeSpanWithFormatResult = 
                ShimsExtensions.TryFormat(testTimeSpanWithFormat,
                    testTimeSpanWithFormatCharsBuffer.AsSpan(), 
                    out var testTimeSpanWithFormatCharsWritten, "G".AsSpan());
            int needWrittenTimeSpanWithFormatChars = 18;
            Assert.Equal(needWrittenTimeSpanWithFormatChars, 
                testTimeSpanWithFormatCharsWritten);
            Assert.True(tryFormatTimeSpanWithFormatResult);
            
            DateTime testDateTime = DateTime.Today;
            char[] testDateTimeCharsBuffer = new char[1024];
            bool tryFormatDateTimeResult = ShimsExtensions.TryFormat(testDateTime,
                testDateTimeCharsBuffer.AsSpan(), out var testDateTimeCharsWritten);
            int needWrittenDateTimeChars = 19;
            Assert.Equal(needWrittenDateTimeChars, testDateTimeCharsWritten);
            Assert.True(tryFormatDateTimeResult);

            char[] testDateTimeEmptyCharsBuffer = Array.Empty<char>();
            bool tryFormatEmptyDateTimeResult = ShimsExtensions.TryFormat(testDateTime,
                testDateTimeEmptyCharsBuffer.AsSpan(), 
                out var testDateTimeEmptyCharsWritten);
            int needWrittenDateTimeEmptyChars = 0;
            Assert.Equal(needWrittenDateTimeEmptyChars, testDateTimeEmptyCharsWritten);
            Assert.False(tryFormatEmptyDateTimeResult);
            
            DateTime testDateTimeWithFormat = DateTime.Today;
            char[] testDateTimeWithFormatCharsBuffer = new char[1024];
            bool tryFormatDateTimeWithFormatResult = ShimsExtensions.TryFormat(testDateTimeWithFormat,
                testDateTimeWithFormatCharsBuffer.AsSpan(), out var testDateTimeWithFormatCharsWritten);
            int needWrittenDateTimeWithFormatChars = 19;
            Assert.Equal(needWrittenDateTimeWithFormatChars, testDateTimeWithFormatCharsWritten);
            Assert.True(tryFormatDateTimeWithFormatResult);

            DateTime testConstDateTime = new DateTime(2022, 1, 1, 12, 15, 30);
            DateTimeOffset testDateTimeOffset = testConstDateTime.ToDateTimeOffset();
            char[] testDateTimeOffsetCharsBuffer = new char[1024];
            bool tryFormatDateTimeOffsetResult = ShimsExtensions.TryFormat(testDateTimeOffset,
                testDateTimeOffsetCharsBuffer.AsSpan(), 
                out var testDateTimeOffsetCharsWritten, "G".AsSpan());
            int needWrittenDateTimeOffsetChars = 19;
            Assert.Equal(needWrittenDateTimeOffsetChars, testDateTimeOffsetCharsWritten);
            Assert.True(tryFormatDateTimeOffsetResult);

            
            char[] testDateTimeOffsetEmptyCharsBuffer = Array.Empty<char>();
            bool tryFormatEmptyDateTimeOffsetResult = ShimsExtensions.TryFormat(testDateTimeOffset,
                testDateTimeOffsetEmptyCharsBuffer.AsSpan(), 
                out var testDateTimeOffsetEmptyCharsWritten);
            int needWrittenDateTimeOffsetEmptyChars = 0;
            Assert.Equal(needWrittenDateTimeOffsetEmptyChars, testDateTimeOffsetEmptyCharsWritten);
            Assert.False(tryFormatEmptyDateTimeOffsetResult);
            
            DateTimeOffset testDateTimeOffsetWithFormat = testConstDateTime.ToDateTimeOffset();
            char[] testDateTimeOffsetWithFormatCharsBuffer = new char[1024];
            bool tryFormatDateTimeOffsetWithFormatResult = ShimsExtensions.TryFormat(testDateTimeOffsetWithFormat,
                testDateTimeOffsetWithFormatCharsBuffer.AsSpan(), 
                out var testDateTimeOffsetWithFormatCharsWritten, "G".AsSpan());
            int needWrittenDateTimeOffsetWithFormatChars = 19;
            Assert.Equal(needWrittenDateTimeOffsetWithFormatChars, testDateTimeOffsetWithFormatCharsWritten);
            Assert.True(tryFormatDateTimeOffsetWithFormatResult);
            
            decimal testDecimal = 123456.789m;
            char[] testDecimalCharsBuffer = new char[1024];
            ShimsExtensions.TryFormat(testDecimal,
                testDecimalCharsBuffer.AsSpan(), out var testDecimalCharsWritten);
            int needWrittenDecimalChars = 10;
            Assert.Equal(needWrittenDecimalChars, testDecimalCharsWritten);
            
            double testDouble = 123456.789;
            char[] testDoubleCharsBuffer = new char[1024];
            ShimsExtensions.TryFormat(testDouble,
                testDoubleCharsBuffer.AsSpan(), out var testDoubleCharsWritten);
            int needWrittenDoubleChars = 10;
            Assert.Equal(needWrittenDoubleChars, testDoubleCharsWritten);
            
            double testFloat = 123456.789f;
            char[] testFloatCharsBuffer = new char[1024];
            ShimsExtensions.TryFormat(testFloat,
                testFloatCharsBuffer.AsSpan(), out var testFloatCharsWritten);
            int needWrittenFloatChars = 14;
            Assert.Equal(needWrittenFloatChars, testFloatCharsWritten);
            
            Single testSingle = 123456.789f;
            char[] testSingleCharsBuffer = new char[1024];
            ShimsExtensions.TryFormat(testSingle,
                testSingleCharsBuffer.AsSpan(), out var testSingleCharsWritten);
            int needWrittenSingleChars = 9;
            Assert.Equal(needWrittenSingleChars, testSingleCharsWritten);

            byte testByte = 0x1;
            char[] testByteCharsBuffer = new char[1024];
            bool tryFormatByteResult = ShimsExtensions.TryFormat(testByte,
                testByteCharsBuffer.AsSpan(), out var testByteCharsWritten);
            int needWrittenByteChars = 1;
            Assert.Equal(needWrittenByteChars, testByteCharsWritten);
            Assert.True(tryFormatByteResult);
            
            byte testByteWithFormat = 0x1;
            char[] testByteWithFormatCharsBuffer = new char[1024];
            bool tryFormatByteWithFormatResult = ShimsExtensions.TryFormat(testByteWithFormat,
                testByteWithFormatCharsBuffer.AsSpan(), 
                out var testByteWithFormatCharsWritten, "X".AsSpan());
            int needWrittenByteWithFormatChars = 1;
            Assert.Equal(needWrittenByteWithFormatChars, testByteWithFormatCharsWritten);
            Assert.True(tryFormatByteWithFormatResult);

            sbyte testSByte = 0x1;
            char[] testSByteCharsBuffer = new char[1024];
            bool tryFormatSByteResult = ShimsExtensions.TryFormat(testSByte,
                testSByteCharsBuffer.AsSpan(), out var testSByteCharsWritten);
            int needWrittenSByteChars = 1;
            Assert.Equal(needWrittenSByteChars, testSByteCharsWritten);
            Assert.True(tryFormatSByteResult);
            
            sbyte testSByteWithFormat = 0x1;
            char[] testSByteWithFormatCharsBuffer = new char[1024];
            bool tryFormatSByteWithFormatResult = ShimsExtensions.TryFormat(testSByteWithFormat,
                testSByteWithFormatCharsBuffer.AsSpan(), 
                out var testSByteWithFormatCharsWritten, "G".AsSpan());
            int needWrittenSByteWithFormatChars = 1;
            Assert.Equal(needWrittenSByteWithFormatChars, testSByteWithFormatCharsWritten);
            Assert.True(tryFormatSByteWithFormatResult);
            
            sbyte testNegativeSByte = -0x1;
            char[] testNegativeSByteCharsBuffer = new char[1024];
            bool tryFormatNegativeSByteResult = ShimsExtensions.TryFormat(testNegativeSByte,
                testNegativeSByteCharsBuffer.AsSpan(), out var testNegativeSByteCharsWritten);
            int needWrittenNegativeSByteChars = 2;
            Assert.Equal(needWrittenNegativeSByteChars, testNegativeSByteCharsWritten);
            Assert.True(tryFormatNegativeSByteResult);
            
            sbyte testNegativeSByteWithFormat = -0x1;
            char[] testNegativeSByteWithFormatCharsBuffer = new char[1024];
            bool tryFormatNegativeSByteWithFormatResult = ShimsExtensions.TryFormat(testNegativeSByteWithFormat,
                testNegativeSByteWithFormatCharsBuffer.AsSpan(), 
                out var testNegativeSByteWithFormatCharsWritten, "X".AsSpan());
            int needWrittenNegativeSByteWithFormatChars = 2;
            Assert.Equal(needWrittenNegativeSByteWithFormatChars, testNegativeSByteWithFormatCharsWritten);
            Assert.True(tryFormatNegativeSByteWithFormatResult);
            
            short testShort = 123;
            char[] testShortCharsBuffer = new char[1024];
            bool tryFormatShortResult = ShimsExtensions.TryFormat(testShort,
                testShortCharsBuffer.AsSpan(), out var testShortCharsWritten);
            int needWrittenShortChars = 3;
            Assert.Equal(needWrittenShortChars, testShortCharsWritten);
            Assert.True(tryFormatShortResult);
            
            short testShortWithFormat = 123;
            char[] testShortWithFormatCharsBuffer = new char[1024];
            bool tryFormatShortWithFormatResult = ShimsExtensions.TryFormat(testShortWithFormat,
                testShortWithFormatCharsBuffer.AsSpan(), 
                out var testShortWithFormatCharsWritten, "G".AsSpan());
            int needWrittenShortWithFormatChars = 3;
            Assert.Equal(needWrittenShortWithFormatChars, testShortWithFormatCharsWritten);
            Assert.True(tryFormatShortWithFormatResult);
            
            short testNegativeShort = -123;
            char[] testNegativeShortCharsBuffer = new char[1024];
            bool tryFormatNegativeShortResult = ShimsExtensions.TryFormat(testNegativeShort,
                testNegativeShortCharsBuffer.AsSpan(), out var testNegativeShortCharsWritten);
            int needWrittenNegativeShortChars = 4;
            Assert.Equal(needWrittenNegativeShortChars, testNegativeShortCharsWritten);
            Assert.True(tryFormatNegativeShortResult);
            
            short testNegativeShortWithFormat = -123;
            char[] testNegativeShortWithFormatCharsBuffer = new char[1024];
            bool tryFormatNegativeShortWithFormatResult = ShimsExtensions.TryFormat(testNegativeShortWithFormat,
                testNegativeShortWithFormatCharsBuffer.AsSpan(), 
                out var testNegativeShortWithFormatCharsWritten, "X".AsSpan());
            int needWrittenNegativeShortWithFormatChars = 4;
            Assert.Equal(needWrittenNegativeShortWithFormatChars, testNegativeShortWithFormatCharsWritten);
            Assert.True(tryFormatNegativeShortWithFormatResult);
            
            ushort testUnsignedShort = 123;
            char[] testUnsignedShortCharsBuffer = new char[1024];
            bool tryFormatUnsignedShortResult = ShimsExtensions.TryFormat(testUnsignedShort,
                testUnsignedShortCharsBuffer.AsSpan(), out var testUnsignedShortCharsWritten);
            int needWrittenUnsignedShortChars = 3;
            Assert.Equal(needWrittenUnsignedShortChars, testUnsignedShortCharsWritten);
            Assert.True(tryFormatUnsignedShortResult);
            
            ushort testUnsignedShortWithFormat = 123;
            char[] testUnsignedShortWithFormatCharsBuffer = new char[1024];
            bool tryFormatUnsignedShortWithFormatResult = ShimsExtensions.TryFormat(testUnsignedShortWithFormat,
                testUnsignedShortWithFormatCharsBuffer.AsSpan(), 
                out var testUnsignedShortWithFormatCharsWritten, "G".AsSpan());
            int needWrittenUnsignedShortWithFormatChars = 3;
            Assert.Equal(needWrittenUnsignedShortWithFormatChars, testUnsignedShortWithFormatCharsWritten);
            Assert.True(tryFormatUnsignedShortWithFormatResult);
            
            int testInteger = 123456;
            char[] testIntegerCharsBuffer = new char[1024];
            bool tryFormatIntResult = ShimsExtensions.TryFormat(testInteger,
                testIntegerCharsBuffer.AsSpan(), out var testIntegerCharsWritten);
            int needWrittenIntegerChars = 6;
            Assert.Equal(needWrittenIntegerChars, testIntegerCharsWritten);
            Assert.True(tryFormatIntResult);
            
            int testIntegerWithFormat = 123456;
            char[] testIntegerWithFormatCharsBuffer = new char[1024];
            bool tryFormatIntWithFormatResult = ShimsExtensions.TryFormat(testIntegerWithFormat,
                testIntegerWithFormatCharsBuffer.AsSpan(), 
                out var testIntegerWithFormatCharsWritten,"G".AsSpan());
            int needWrittenIntegerWithFormatChars = 6;
            Assert.Equal(needWrittenIntegerWithFormatChars, testIntegerWithFormatCharsWritten);
            Assert.True(tryFormatIntWithFormatResult);

            uint testUnsignedInt = 123456;
            char[] testUnsignedIntCharsBuffer = new char[1024];
            bool tryFormatUnsignedIntResult = ShimsExtensions.TryFormat(testUnsignedInt,
                testUnsignedIntCharsBuffer.AsSpan(), out var testUnsignedIntCharsWritten);
            int needWrittenUnsignedIntChars = 6;
            Assert.Equal(needWrittenUnsignedIntChars, testUnsignedIntCharsWritten);
            Assert.True(tryFormatUnsignedIntResult);
            
            uint testUnsignedIntWithFormat = 123456;
            char[] testUnsignedIntWithFormatCharsBuffer = new char[1024];
            bool tryFormatUnsignedIntWithFormatResult = ShimsExtensions.TryFormat(testUnsignedIntWithFormat,
                testUnsignedIntWithFormatCharsBuffer.AsSpan(), 
                out var testUnsignedIntWithFormatCharsWritten, "G".AsSpan());
            int needWrittenUnsignedIntWithFormatChars = 6;
            Assert.Equal(needWrittenUnsignedIntWithFormatChars, testUnsignedIntWithFormatCharsWritten);
            Assert.True(tryFormatUnsignedIntWithFormatResult);
            
            long testLong = 123456789;
            char[] testLongCharsBuffer = new char[1024];
            bool tryFormatLongResult = ShimsExtensions.TryFormat(testLong,
                testLongCharsBuffer.AsSpan(), out var testLongCharsWritten);
            int needWrittenLongChars = 9;
            Assert.Equal(needWrittenLongChars, testLongCharsWritten);
            Assert.True(tryFormatLongResult);
            
            long testLongWithFormat = 123456789;
            char[] testLongWithFormatCharsBuffer = new char[1024];
            bool tryFormatLongWithFormatResult = ShimsExtensions.TryFormat(testLongWithFormat,
                testLongWithFormatCharsBuffer.AsSpan(), 
                out var testLongWithFormatCharsWritten, "G".AsSpan());
            int needWrittenLongWithFormatChars = 9;
            Assert.Equal(needWrittenLongWithFormatChars, testLongWithFormatCharsWritten);
            Assert.True(tryFormatLongWithFormatResult);
            
            ulong testUnsignedLong = 123456789;
            char[] testUnsignedLongCharsBuffer = new char[1024];
            bool tryFormatUnsignedLongResult = ShimsExtensions.TryFormat(testUnsignedLong,
                testUnsignedLongCharsBuffer.AsSpan(), out var testUnsignedLongCharsWritten);
            int needWrittenUnsignedLongChars = 9;
            Assert.Equal(needWrittenUnsignedLongChars, testUnsignedLongCharsWritten);
            Assert.True(tryFormatUnsignedLongResult);
            
            ulong testUnsignedLongWithFormat = 123456789;
            char[] testUnsignedLongWithFormatCharsBuffer = new char[1024];
            bool tryFormatUnsignedLongWithFormatResult = ShimsExtensions.TryFormat(testUnsignedLongWithFormat,
                testUnsignedLongWithFormatCharsBuffer.AsSpan(), 
                out var testUnsignedLongWithFormatCharsWritten, "G".AsSpan());
            int needWrittenUnsignedLongWithFormatChars = 9;
            Assert.Equal(needWrittenUnsignedLongWithFormatChars, testUnsignedLongWithFormatCharsWritten);
            Assert.True(tryFormatUnsignedLongWithFormatResult);
        }

        [Fact]
        public void GetFormatTest()
        {
        }
        
    }
}